﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;

namespace ESpace
{
    [ToolboxBitmap(typeof(EChatWindow), "EWindowChatIcon.bmp")]
    public class EChatWindow : Control
    {
        Font[] fnt = new Font[4] { new Font("Arial", 10), new Font("Arial", 10, FontStyle.Bold), new Font("Arial", 10, FontStyle.Italic), new Font("Arial", 10, FontStyle.Bold | FontStyle.Italic) };
        bool bFirst = true;
        List<TextStlitter.StringList> sl = new List<TextStlitter.StringList>();
        Timer tmr = new Timer();

        public List<EGif> imL = new List<EGif>();
        
        bool bScroll = false;

        int scrPos;
        int scrMax;
        int scrW = 20;
        bool scrDown = false;
        bool scrBtm = false;

        #region *** свойства *********************************************************

        [DefaultValue(false)]
        public bool ScrollAlwaysInBottom
        {
            get { return scrBtm; }
            set
            {
                scrBtm = value;
                if (scrBtm)
                {
                    scrPos = scrMax;
                    DrawAll();
                }
            }
        }

        [DefaultValue(10f)]
        public float FontSize
        {
            get { return fnt[0].Size; }
            set
            {
                if (value < 1) return;
                fnt[0] = new Font("Arial", value);
                fnt[1] = new Font("Arial", value, FontStyle.Bold);
                fnt[2] = new Font("Arial", value, FontStyle.Italic);
                fnt[3] = new Font("Arial", value, FontStyle.Bold | FontStyle.Italic);
                SplitAllText();
                ResetScroll();
                if (scrBtm)
                {
                    scrPos = scrMax;
                }
                DrawAll();
            }
        }

        public override string Text
        {
            get
            {
                return text;
            }
            set
            {
                text = value;
                SplitAllText();
                ResetScroll();
                if (scrBtm)
                {
                    scrPos = scrMax;
                }
                DrawAll();
            }
        }

        public override Color BackColor
        {
            get
            {
                return base.BackColor;
            }
            set
            {
                base.BackColor = value;
                pnBk.Color = BackColor;
                DrawAll();
            }
        }

        //Color clrBk = Color.White;
        Pen pnBk = new Pen(SystemColors.Control);
        Pen pnBrd = new Pen(Color.SkyBlue);
        
        [DefaultValue(typeof(Color),"SkyBlue")]
        public Color BorderColor
        {
            get { return pnBrd.Color; }
            set { pnBrd.Color = value; DrawAll(); }
        }

        #endregion *** свойства *********************************************************

        String text = "";
        
        public EChatWindow()
        {
            tmr.Interval = 50;
            tmr.Enabled = true;
            tmr.Tick += new EventHandler(tmr_tick);
        }

        float elTime = 0;
        string FPS = "";

        protected void tmr_tick(object sender, EventArgs e)
        {
            elTime = Utility.GetElapsedTime();
            
                FPS = (1 / elTime).ToString("F2");
               
            bool bDraw = false;
            for (int i = 0; i < imL.Count; i++)
            {
                if (imL[i].Run(elTime * 1000.0) && imL[i].b) bDraw = true;
            }
            if(bDraw) DrawAll();
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            DrawAll();
            //base.OnPaint(e);
        }

        protected override void OnResize(EventArgs e)
        {
            SplitAllText();
            ResetScroll();
            DrawAll();
            base.OnResize(e);
        }

        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (bScroll)
            {
                if (e.X > (Width - scrW))
                {
                    scrPos = e.Y - (scrW - 4) / 2 - 1;
                    scrPos = (int)(scrPos*PointScrOnPixel());
                    if (scrPos < 0) scrPos = 0;
                    if (scrPos > scrMax) scrPos = scrMax;
                    DrawAll();
                    scrDown = true;
                }
            }
            base.OnMouseDown(e);
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            if (bScroll && scrDown)
            {
                scrPos = e.Y - (scrW - 4) / 2 - 1;
                scrPos = (int)(scrPos * PointScrOnPixel());
                if (scrPos < 0) scrPos = 0;
                if (scrPos > scrMax) scrPos = scrMax;
                DrawAll();
            }
            base.OnMouseMove(e);
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            scrDown = false;
            base.OnMouseUp(e);
        }

        protected override void OnMouseWheel(MouseEventArgs e)
        {
            base.OnMouseWheel(e);
        }

        void SplitAllText()
        {
            sl.Clear();
            if (bScroll) TextStlitter.SplText(sl, text, Width - 10-scrW, fnt[0], GetSizeTag);
            else TextStlitter.SplText(sl, text, Width - 10, fnt[0], GetSizeTag);
        }

        void SplitAddText(String str)
        {
            if (bScroll) TextStlitter.SplText(sl, str, Width - 10 - scrW, fnt[0], GetSizeTag);
            else TextStlitter.SplText(sl, str, Width - 10, fnt[0], GetSizeTag);
        }

        public void AddText(String s)
        {
            SplitAddText(s);
            text += s;
            ResetScroll();
            if (scrBtm)
            {
                scrPos = scrMax;
            }
            DrawAll();
        }

        Size GetSizeTag(String s)
        {
            int n = GetImageIdByTag(s);
            if (n != -1) return new Size(imL[n].Width, imL[n].Height+5);
            Color clr = GetColorByTag(s);
            if (clr != Color.Transparent) return new Size(0, 0);
            if(GetStyleByTag(s)!=(char)0) return new Size(0, 0);

            return new Size(-1, -1);
        }

        char GetStyleByTag(String s)
        {
            if (s.Length != 3) return (char)0;
            return s[1];
        }

        int GetImageIdByTag(String s)
        {
            int n = 0;
            if (s.Length == 5)
                if (int.TryParse(s.Substring(1, 3), out n))
                    if (n >= 0 & n < imL.Count)
                        return n;
            return -1;
        }

        Color GetColorByTag(String s)
        {
            if (s.Length != 17) return Color.Transparent;
            if (s.Substring(1, 3) != "clr") return Color.Transparent;
            byte R = 0;
            byte G = 0;
            byte B = 0;
            if (!byte.TryParse(s.Substring(5, 3), out R)) return Color.Transparent;
            if (!byte.TryParse(s.Substring(9, 3), out G)) return Color.Transparent;
            if (!byte.TryParse(s.Substring(13, 3), out B)) return Color.Transparent;
            return Color.FromArgb(R, G, B);
        }

        void DrawAll()
        {
            if (Width == 0 || Height == 0) return;
            if (bFirst)
            {
                bFirst = false;
                Text = "";
            }

            for (int i = 0; i < imL.Count; i++)
                imL[i].b = false;

            Graphics grC = Graphics.FromHwnd(Handle);
            Bitmap bmp = new Bitmap(Width, Height);
            Graphics gr = Graphics.FromImage(bmp);
            gr.Clear(BackColor);
            gr.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
            Color fntColor = Color.Black;
            int fntNum = 0;
            for (int i = 0; i < sl.Count; i++)
            {
                for (int j = 0; j < sl[i].strL.Count; j++)
                {
                    // рисуем только видимое + 1 стока снизу
                    int btm = sl[i].y + sl[i].h; // низ  строки
                    int top = sl[i].y - sl[i].shH; // верх строки
                    if (btm < scrPos || top > (scrPos + Height)) continue;

                    // если это тег
                    if (sl[i].strL[j].tag)
                    {
                        int n = GetImageIdByTag(sl[i].strL[j].s);
                        if (n != -1)
                        {
                            gr.DrawImage(imL[n].ActBmp, sl[i].strL[j].x + 5, sl[i].y - scrPos - (imL[n].Height - sl[i].h));
                            imL[n].b = true;
                            continue;
                        }
                        
                        Color clr = GetColorByTag(sl[i].strL[j].s);
                        if (clr != Color.Transparent)
                        {
                            fntColor = clr;
                            continue;
                        }

                        char ch = GetStyleByTag(sl[i].strL[j].s);
                        if (ch != (char)0)
                        {
                            if (ch == 'n') fntNum = 0;
                            if (ch == 'b') fntNum = 1;
                            if (ch == 'i') fntNum = 2;
                            if (ch == 'm') fntNum = 3;
                            continue;
                        }
                    }

                    TextRenderer.DrawText(gr, sl[i].strL[j].s, fnt[fntNum], new Point(sl[i].strL[j].x + 5, sl[i].y - scrPos), fntColor);
                   
                }
            }

            // скролл
            DrawScroll(gr);
            // рамка
            gr.DrawRectangle(pnBrd, 0, 0, Width - 1, Height - 1);
            int w = Width - 3;
            if (bScroll) w -= scrW;
            gr.DrawRectangle(pnBk, 1, 1, w, Height - 3);
        
            grC.DrawImage(bmp, 0, 0);
            bmp.Dispose();
            gr.Dispose();
            grC.Dispose();
        }

        // сколько в одном пикселе поинтов скрола
        double PointScrOnPixel()
        {
            int h = sl[sl.Count - 1].y + sl[sl.Count - 1].h;
            int Max = (h - (Height - 10));
            return Max / (double)(Height - 2 - scrW);

        }

        void ResetScroll()
        {
            int h = 5;
            if (sl.Count == 0) scrMax = 0;
            else
            {
                h = sl[sl.Count - 1].y + sl[sl.Count - 1].h;
                scrMax = (h - (Height - 10));
            }
            if (scrMax < 0) scrMax = 0;
            if (scrPos > scrMax) scrPos = scrMax;

            if ((!bScroll & scrMax > 0) || (bScroll & scrMax == 0))
            {
                bScroll = !bScroll;
                SplitAllText();
                ResetScroll();
            }
        }

        void DrawScroll(Graphics gr)
        {
            if (!bScroll) return;

            gr.FillRectangle(Brushes.Thistle, Width - scrW, 1, scrW - 1, Height - 2);
            gr.DrawLine(pnBrd, Width - scrW, 1, Width - scrW, Height - 2);
            int w = scrW - 4; // размер ползунка
            int y = (int)(scrPos / PointScrOnPixel()) + 2;
            gr.FillRectangle(Brushes.SkyBlue, Width - scrW + 2, y, w, w+2);
            gr.FillRectangle(Brushes.LightCyan, Width - scrW + 2, y, w -1, w + 2 - 1);
        }

    }
}
